﻿using Sgr.Caching.Services;
using Sgr.Generator;

namespace Sgr.Trackers
{
    public class MessageTokenByMemory : IMessageToken
    {
        private static object lockObj = new object();

        private readonly ICacheManager _cacheManager;
        private readonly IStringIdGenerator _stringIdGenerator;

        public MessageTokenByMemory(IStringIdGenerator stringIdGenerator, ICacheManager cacheManager)
        {
            _stringIdGenerator = stringIdGenerator;
            _cacheManager = cacheManager;
        }

        /// <summary>
        /// 颁发令牌
        /// </summary>
        /// <param name="effectiveSecond">有效期，单位秒（默认1天）</param>
        /// <param name="token"></param>
        /// <returns></returns>
        public async Task<string> IssuingTokenAsync(int effectiveSecond = 86400, CancellationToken token = default)
        {
            string key = _stringIdGenerator.GenerateUniqueId();
            await _cacheManager.SetAsync(key, "X", _cacheManager.CreateCacheEntryOptions().SetAbsoluteExpirationRelativeToNowSecond(effectiveSecond), token);
            return key;
        }

        /// <summary>
        /// 验证令牌
        /// </summary>
        /// <param name="key"></param>
        /// <param name="token"></param>
        /// <returns></returns>
        public async Task<bool> VerifyTokenAsync(string key, CancellationToken token = default)
        {
            //验证令牌是否存在
            bool hasKey = true;
            bool lockWasTaken = false;
            try
            {
                System.Threading.Monitor.Enter(lockObj, ref lockWasTaken);

                _cacheManager.Get(key, () =>
                {
                    hasKey = false;
                    return "_";
                },
               _cacheManager.CreateCacheEntryOptions().SetAbsoluteExpirationRelativeToNowSecond(3));
                //移除令牌
                await _cacheManager.RemoveAsync(key, token);
            }
            catch
            {
                hasKey = false;
            }
            finally
            {
                if (lockWasTaken) System.Threading.Monitor.Exit(lockObj);
            }

            //返回
            return hasKey;
        }
    }
}